package com.way.demo.comm.exception;

import com.way.demo.comm.result.ApiCode;
import com.way.demo.comm.result.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * @author lipingwei
 * @create 2021-07-05 14:27
 * https://www.cnblogs.com/austinspark-jessylu/p/13265334.html
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * Sql 异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = BadSqlGrammarException.class)
    public ApiResult handleException(BadSqlGrammarException e){
        log.error(e.getMessage(), e);
        return  ApiResult.result(ApiCode.BAD_SQL_GRAMMAR_ERROR);
    }

    /**
     * controller 参数校验非空异常
     * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult handleException(MethodArgumentNotValidException e){
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
        return ApiResult.fail(message);
    }

    /**
     * //处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，
     * @param e
     * @return
     */
    @ExceptionHandler({BindException.class})
    public ApiResult handleException(BindException e){
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
        return ApiResult.fail(message);
    }

    /**
     *
     * @param e
     * @return
     * 拦截 get请求时， @RequestParam 与 @PathVariable 拦截异常
     * 注：必须在controller 类上加 @Validated才会生效；（@valid无效）
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public ApiResult handleException(ConstraintViolationException e){
        log.error(e.getMessage(), e);
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
        return ApiResult.fail(message);
    }





    /**
     * 业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public ApiResult handleException(BusinessException e){
        log.error(e.getMessage(), e);
        return ApiResult.fail(e.getCode(),e.getMessage());
    }

    /**
     * 系统未知异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public ApiResult handleException(Exception e){
        log.error(e.getMessage(), e);
        return ApiResult.result(ApiCode.FAIL);
    }

    /**
     * 进入controller 之前的异常
     */
    @ExceptionHandler({
            NoHandlerFoundException.class,
            HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class,
            MissingPathVariableException.class,
            MissingServletRequestParameterException.class,
            TypeMismatchException.class,
            HttpMessageNotReadableException.class, //数据绑定异常
            HttpMessageNotWritableException.class,
           // MethodArgumentNotValidException.class,
            HttpMediaTypeNotAcceptableException.class,
            ServletRequestBindingException.class,
            ConversionNotSupportedException.class,
            MissingServletRequestPartException.class,
            AsyncRequestTimeoutException.class
    })
    public ApiResult handleServletException(Exception e){
        log.error(e.getMessage(), e);
        return ApiResult.fail(e.getMessage());
    }

}
